package com.cy.milktea.service.impl;

import com.cy.milktea.mapper.OrderInfoMapper;
import com.cy.milktea.mapper.OrderMapper;
import com.cy.milktea.pojo.Goods;
import com.cy.milktea.pojo.System.Redis;
import com.cy.milktea.pojo.Order;
import com.cy.milktea.pojo.QueuingOrder;
import com.cy.milktea.service.OrderService;
import com.cy.milktea.service.WXService;
import com.cy.milktea.utils.PageHelperUtils;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl implements OrderService {

    private static final String[] headGroup = new String[]{"A", "B", "C", "D"};
    private static final long size = 100L; //--->A + 0~99

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private WXService wxService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderInfoMapper orderInfoMapper;


    /* 完成订单 */
    @Override
    public void finish(QueuingOrder order) {
        //删除redis中排队的订单
        deleteBySortIdOnQueue(order.getSortId());
        //设置订单状态 2:已完成
        order.setOrderStatus(2);
        //设置顾客接受商品的时间
        order.setReceiveTime(new Date());
        orderMapper.update(order);
    }

    /* 查询历史订单 */
    @Override
    public PageHelperUtils.PageInfo<Order> queryHistory(String orderID, Date minDate, Date maxDate, String sort) {
        List<Order> orderList = orderMapper.select(orderID, minDate, maxDate, sort);
        PageHelperUtils.PageInfo<Order> pageInfo = PageHelperUtils.startPage(orderList);
        pageInfo.getList().forEach(order -> {
            order.getOrderInfo().getGoodsList().forEach(Goods::unJsonToDrink);
        });
        return pageInfo;
    }


    /* 在redis中创建订单并存一份到数据库中 */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public QueuingOrder createOnQueue(QueuingOrder order) {
        //计算当前订单总费用
        order.totalCost();
        //生成订单描述
        order.createDrinkDesc();
        //生成订单号
        order.setOrderID(createOrderID());
        //订单状态为'0:支付成功'
        order.setOrderStatus(1);
        //支付状态为'0:已经支付'
        order.setPayStatus(1);
        //设置下单时间:
        order.setToOrderTime(new Date());
        //设置支付时间:
        order.setPayTime(new Date());
        //设置排队号和相对位置并存入redis的订单队列中(原子操作)
        addOueuingOrder(order);
        //存入到数据库中
        orderMapper.insert(order);
        order.getOrderInfo().setOrderID(order.getOrderID());
        orderInfoMapper.insert(order.getOrderInfo());
        return order;
    }

    /* 查询redis中排队的所有订单 */
    @Override
    public List<QueuingOrder> queryCurrentQueue() {
        return queryQueueAll();
    }

    /* 查询redis中排队的某个订单 */
    @Override
    public QueuingOrder queryCurrentBySortIdOnQueue(String sortId) {
        return queryQueueOne(sortId);
    }

    /* 删除redis中的某个订单 */
    @Override
    public void deleteBySortIdOnQueue(String sortId) {
        if (StringUtils.hasLength(sortId)) {
            deleteQueuingOrder(sortId);
        }
    }


    private String createOrderID() {
        Long increment = redisTemplate.opsForValue().increment(Redis.ORDER_ID_INDEX);
        String dateStr = new SimpleDateFormat("yyyMMdd").format(new Date());
        return dateStr + redisTemplate.opsForList().index(Redis.ORDER_ID_LIST, increment);
    }

    /* 添加排队订单 */
    private void addOueuingOrder(QueuingOrder order) {
        for (int i = 0; i < 30; i++) {
            //获取锁
            if (redisTemplate.opsForValue().setIfAbsent(Redis.ORDER_QUEUE_LOCK, null)) {
                try {
                    //设置2秒后自动释放锁
                    redisTemplate.expire(Redis.ORDER_QUEUE_LOCK, 2, TimeUnit.SECONDS);
                    //获取队列相对位置
                    Integer relative = (Integer) redisTemplate.opsForValue().get(Redis.ORDER_QUEUE_VALUE);
                    //获取队列大小
                    long queueSize = redisTemplate.opsForHash().size(Redis.QUEUING_ORDERS);
                    order.setRelativePosition((int) (relative + queueSize));
                    //获取排队号
                    long sort = redisTemplate.opsForValue().increment(Redis.ORDER_SORT_VALUE);
                    String sortId = headGroup[(int) (sort / size) % headGroup.length] + sort % size;
                    order.setSortId(sortId);
                    //添加redis队列中
                    redisTemplate.opsForHash().put(Redis.QUEUING_ORDERS, sortId, order);
                } finally {
                    //释放锁
                    redisTemplate.delete(Redis.ORDER_QUEUE_LOCK);
                }
                return;
            } else {
                try {
                    //线程睡眠100ms再次查询
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                throw new RuntimeException("订单队列阻塞异常!");
            }
        }
    }

    /* 删除排队订单 */
    private void deleteQueuingOrder(String sortId) {
        for (int i = 0; i < 30; i++) {
            //获取锁
            if (redisTemplate.opsForValue().setIfAbsent(Redis.ORDER_QUEUE_LOCK, null)) {
                try {
                    //设置2秒后自动释放锁
                    redisTemplate.expire(Redis.ORDER_QUEUE_LOCK, 2, TimeUnit.SECONDS);
                    //相对位置加1
                    redisTemplate.opsForValue().increment(Redis.ORDER_QUEUE_VALUE);
                    //删除对应排队号的订单
                    long delete = redisTemplate.opsForHash().delete(Redis.QUEUING_ORDERS, sortId);
                    break;
                } finally {
                    //释放锁
                    redisTemplate.delete(Redis.ORDER_QUEUE_LOCK);
                }
            } else {
                try {
                    //线程睡眠100ms再次查询
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /* 查询所有排队订单(后台查询) */
    private List<QueuingOrder> queryQueueAll() {
        List<Object> list = redisTemplate.opsForHash().values(Redis.QUEUING_ORDERS);
        Integer value = (Integer) redisTemplate.opsForValue().get(Redis.ORDER_QUEUE_VALUE);
        List<QueuingOrder> orderList = new ArrayList<>();
        for (Object o : list) {
            QueuingOrder order = (QueuingOrder) o;
            order.setAbsolutePosition(order.getRelativePosition() - value);
            orderList.add(order);
        }
        //升序
        orderList.sort(((o1, o2) -> o1.getAbsolutePosition() > o2.getAbsolutePosition() ? 1 : -1));
        return orderList;
    }

    /* 根据排队号查询(顾客查询) */
    private QueuingOrder queryQueueOne(String sortId) {
        QueuingOrder order = null;
        if (StringUtils.hasLength(sortId)) {
            order = (QueuingOrder) redisTemplate.opsForHash().get(Redis.QUEUING_ORDERS, sortId);
            Integer value = (Integer) redisTemplate.opsForValue().get(Redis.ORDER_QUEUE_VALUE);
            order.setAbsolutePosition(order.getRelativePosition() - value);
        }
        return order;
    }

}




















